Extra: Venue 7 electrics#

If you see a straight line, it’s interpolated missing data. Try the sliders to see detail!

import plotly.graph_objects as go
import numpy as np
import pandas as pd

df = pd.read_csv("venue-7-clampon-data.csv")
df["timestamp"] = pd.to_datetime(df['created_at'])
df = df.fillna(value=0)

phase1trace = go.Scatter(customdata=df, 
                    y=df['field1'], 
                    x = df['timestamp'], 
                    mode='lines', 
                    hoverinfo='all', 
                    name='phase 1',
                    )

phase2trace = go.Scatter(customdata=df, 
                    y=df['field2'], 
                    x = df['timestamp'], 
                    mode='lines', 
                    hoverinfo='all', 
                    name='phase 2',
                    )
phase3trace = go.Scatter(customdata=df, 
                    y=df['field3'], 
                    x = df['timestamp'], 
                    mode='lines', 
                    hoverinfo='all', 
                    name='phase 3',
                    )

g = go.FigureWidget(data=[phase1trace,phase2trace,phase3trace])
g.layout.title = 'CurrentCost clamp-on meter readings'
g.layout.xaxis.title= 'timestamp'
g.layout.yaxis.title = "Watts"
g.layout.width = 1000
g.layout.height = 500

fig = go.Figure(g)

fig.update_layout(
    hovermode='x unified',
    hoverlabel=dict(
        bgcolor="white",
        # font_size=16,
        font_family="Rockwell"
    )
)

# Add range slider
fig.update_layout(
    xaxis=dict(
        rangeselector=dict(
            buttons=list([
                dict(
                     label="All",
                     step="all"
                     ),
                                dict(count=1,
                     label="Hour",
                     step="hour",
                     stepmode="todate"),
                dict(count=1,
                     label="Day",
                     step="day",
                     stepmode="backward"),
                dict(count=7,
                     label="Week",
                     step="day",
                     stepmode="backward"),
                dict(count=1,
                     label="Year",
                     step="year",
                     stepmode="backward")
            ])
        ),
        rangeslider=dict(
            visible=True,
        ),
        type="date"
    )
)


# fig.update_yaxes(range=[50, 60])  



# fig.update_yaxes(range = [-5, df['temperature'].max()+5])

fig.show()

# second figure 

sumtrace = go.Scatter(customdata=df, 
                    y=df['field1'] + df['field2'] + df['field3'], 
                    x = df['timestamp'], 
                    mode='lines', 
                    hoverinfo='all', 
                    name='sum of three phases',
                    )

g2 = go.FigureWidget(data=[sumtrace])
g2.layout.title = 'CurrentCost clamp-on meter readings - simple sum of phases'
g2.layout.xaxis.title= 'timestamp'
g2.layout.yaxis.title = "Watts"
g2.layout.width = 1000
g2.layout.height = 500

fig2 = go.Figure(g2)

fig2.update_layout(
    hovermode='x unified',
    hoverlabel=dict(
        bgcolor="white",
        # font_size=16,
        font_family="Rockwell"
    )
)

# Add range slider
fig2.update_layout(
    xaxis=dict(
        rangeselector=dict(
            buttons=list([
                dict(
                     label="All",
                     step="all"
                     ),
                                dict(count=1,
                     label="Hour",
                     step="hour",
                     stepmode="todate"),
                dict(count=1,
                     label="Day",
                     step="day",
                     stepmode="backward"),
                dict(count=7,
                     label="Week",
                     step="day",
                     stepmode="backward"),
                dict(count=1,
                     label="Year",
                     step="year",
                     stepmode="backward")
            ])
        ),
        rangeslider=dict(
            visible=True,
        ),
        type="date"
    )
)


fig2.show()
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
Cell In[1], line 110
    107 g2.layout.width = 1000
    108 g2.layout.height = 500
--> 110 fig2 = go.Figure(g2)
    112 fig2.update_layout(
    113     hovermode='x unified',
    114     hoverlabel=dict(
   (...)
    118     )
    119 )
    121 # Add range slider

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/site-packages/plotly/graph_objs/_figure.py:616, in Figure.__init__(self, data, layout, frames, skip_invalid, **kwargs)
      5 def __init__(
      6     self, data=None, layout=None, frames=None, skip_invalid=False, **kwargs
      7 ):
      8     """
      9     Create a new :class:Figure instance
     10 
   (...)
    614         is invalid AND skip_invalid is False
    615     """
--> 616     super(Figure, self).__init__(data, layout, frames, skip_invalid, **kwargs)

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/site-packages/plotly/basedatatypes.py:514, in BaseFigure.__init__(self, data, layout_plotly, frames, skip_invalid, **kwargs)
    511 self._data_validator = DataValidator(set_uid=self._set_trace_uid)
    513 # ### Import traces ###
--> 514 data = self._data_validator.validate_coerce(
    515     data, skip_invalid=skip_invalid, _validate=self._validate
    516 )
    518 # ### Save tuple of trace objects ###
    519 self._data_objs = data

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/site-packages/_plotly_utils/basevalidators.py:2648, in BaseDataValidator.validate_coerce(self, v, skip_invalid, _validate)
   2645     v_el = v_el.to_plotly_json()
   2647 if isinstance(v_el, dict):
-> 2648     v_copy = deepcopy(v_el)
   2650     if "type" in v_copy:
   2651         trace_type = v_copy.pop("type")

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/copy.py:230, in _deepcopy_dict(x, memo, deepcopy)
    228 memo[id(x)] = y
    229 for key, value in x.items():
--> 230     y[deepcopy(key, memo)] = deepcopy(value, memo)
    231 return y

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/copy.py:153, in deepcopy(x, memo, _nil)
    151 copier = getattr(x, "__deepcopy__", None)
    152 if copier is not None:
--> 153     y = copier(memo)
    154 else:
    155     reductor = dispatch_table.get(cls)

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/copy.py:264, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    262 if deep and args:
    263     args = (deepcopy(arg, memo) for arg in args)
--> 264 y = func(*args)
    265 if deep:
    266     memo[id(x)] = y

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/copy.py:263, in <genexpr>(.0)
    261 deep = memo is not None
    262 if deep and args:
--> 263     args = (deepcopy(arg, memo) for arg in args)
    264 y = func(*args)
    265 if deep:

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/copy.py:138, in deepcopy(x, memo, _nil)
    135     memo = {}
    137 d = id(x)
--> 138 y = memo.get(d, _nil)
    139 if y is not _nil:
    140     return y

KeyboardInterrupt: 

It’s complicated to know how much electricity is drawn from the three phases of a meter - it’s not just a case of adding the three phases up. But this will give some idea.

This plot is interesting because it shows a minimum of around 2 kW base load with lots of 2.5 kW spikes even when the building is unoccupied. If that electricity isn’t doing useful work, getting those under control could substantially cut the electricity bill. The equipment we are using isn’t very common and we only have one set, but getting a smart meter is another way of seeing this kind of information. Admittedly, with half hourly readings a smart meter isn’t nearly as informative. This is roughly what the same data would look like with a smart meter.



# downsample to every 30 minutes

df.field1 = df.field1.astype(int)
df.field2 = df.field2.astype(int) 
df.field3 = df.field3.astype(int)

# aggregate over 30 minute intervals - this is the interval for smart meter readings.
s = df.resample('30T', on='timestamp', origin='start').agg({'field1':'mean','field2':'mean','field3':'mean'})
s['timestamp'] = s.index 
s = s.fillna(value=0)

downsampled1 = go.Scatter(customdata=s, 
                    y=s['field1']/1000, 
                    x = s['timestamp'], 
                    mode='lines', 
                    hoverinfo='all', 
                    name='phase 1',
                    )
downsampled2 = go.Scatter(customdata=s, 
                    y=s['field2']/1000, 
                    x = s['timestamp'], 
                    mode='lines', 
                    hoverinfo='all', 
                    name='phase 2',
                    )
downsampled3 = go.Scatter(customdata=s, 
                    y=s['field3']/1000, 
                    x = s['timestamp'], 
                    mode='lines', 
                    hoverinfo='all', 
                    name='phase 3',
                    )

g3 = go.FigureWidget(data=[downsampled1, downsampled2, downsampled3])
g3.layout.title = 'CurrentCost clamp-on meter readings - aggregated for half hour slots'
g3.layout.xaxis.title= 'timestamp'
g3.layout.yaxis.title = "kW"
g3.layout.width = 1000
g3.layout.height = 500

fig3 = go.Figure(g3)

fig3.update_layout(
    hovermode='x unified',
    hoverlabel=dict(
        bgcolor="white",
        # font_size=16,
        font_family="Rockwell"
    )
)

# Add range slider
fig3.update_layout(
    xaxis=dict(
        rangeselector=dict(
            buttons=list([
                dict(
                     label="All",
                     step="all"
                     ),
                                dict(count=1,
                     label="Hour",
                     step="hour",
                     stepmode="todate"),
                dict(count=1,
                     label="Day",
                     step="day",
                     stepmode="backward"),
                dict(count=7,
                     label="Week",
                     step="day",
                     stepmode="backward"),
                dict(count=1,
                     label="Year",
                     step="year",
                     stepmode="backward")
            ])
        ),
        rangeslider=dict(
            visible=True,
        ),
        type="date"
    )
)


fig3.show()